// 自定义错误处理包，支持记录错误的发生我位置、发生行数等信息
package xerror

import (
	"errors"
	"fmt"
	"runtime"
)

// 定义错误结构体，此结构体直接使用F公共变量，以便使用时直接调用，而不需要再行获取
type XError struct {
	File   string `json:"file" form:"file"`     // 错误文件
	Line   int    `json:"line" form:"line"`     // 错误行数
	Errors string `json:"errors" form:"errors"` // 错误信息
}

// 错误信息输出
func (c *XError) Error() string {
	return c.Errors
}

// 输出详细的字符串信息
func (c *XError) ErrorInfo() string {
	return fmt.Sprintf("%s:%d\t%s", c.File, c.Line, c.Errors)
}

// 新建错误消息
//
//	msg	错误消息
func New(msg string) error {
	_, file, line, _ := runtime.Caller(1)
	return &XError{
		File:   file,
		Line:   line,
		Errors: msg,
	}
}

// 新建错误消息-带参数格式化形式
//
//	msg		错误消息
//	param	传入参数
func NewFmt(msg string, param ...any) error {
	_, file, line, _ := runtime.Caller(1)
	return &XError{
		File:   file,
		Line:   line,
		Errors: fmt.Sprintf(msg, param...),
	}
}

// 新建错误信息
//
//	msg	错误提示
//	err	错误信息
func NewError(msg string, err error) error {
	if err == nil {
		_, file, line, _ := runtime.Caller(1)
		return &XError{
			File:   file,
			Line:   line,
			Errors: msg,
		}
	}
	return err
}

// 将error错误信息转换为xerror.XError对象，便于更加完善的错误记录
// 自动判定，如果err为xerror.XError对象，则会直接将err进行返回，并不会做进一步封装
//
//	err	待转换的错误对象
func To(err error) error {
	if err == nil {
		return nil
	}
	var errs *XError
	if errors.As(err, &errs) {
		return err
	}
	_, file, line, _ := runtime.Caller(1)
	return &XError{
		File:   file,
		Line:   line,
		Errors: err.Error(),
	}
}
